/*
 * Copyright (c) 2015-2025 The Khronos Group Inc.
 * Copyright (c) 2015-2025 Valve Corporation
 * Copyright (c) 2015-2025 LunarG, Inc.
 * Copyright (c) 2015-2025 Google, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 */

#include "../framework/layer_validation_tests.h"

void ImageDrmTest::InitBasicImageDrm() {
    SetTargetApiVersion(VK_API_VERSION_1_2);  // required extension added here
    AddRequiredExtensions(VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
    RETURN_IF_SKIP(Init());
}

std::vector<uint64_t> ImageDrmTest::GetFormatModifier(VkFormat format, VkFormatFeatureFlags2 features, uint32_t plane_count) {
    std::vector<uint64_t> mods;
    VkDrmFormatModifierPropertiesListEXT mod_props = vku::InitStructHelper();
    VkFormatProperties2 format_props = vku::InitStructHelper(&mod_props);
    vk::GetPhysicalDeviceFormatProperties2(Gpu(), format, &format_props);
    if (mod_props.drmFormatModifierCount == 0) {
        return mods;
    }

    std::vector<VkDrmFormatModifierPropertiesEXT> mod_props_length(mod_props.drmFormatModifierCount);
    mod_props.pDrmFormatModifierProperties = mod_props_length.data();
    vk::GetPhysicalDeviceFormatProperties2(Gpu(), format, &format_props);

    for (uint32_t i = 0; i < mod_props.drmFormatModifierCount; ++i) {
        auto &mod = mod_props.pDrmFormatModifierProperties[i];
        if (((mod.drmFormatModifierTilingFeatures & features) == features) && (plane_count == mod.drmFormatModifierPlaneCount)) {
            mods.push_back(mod.drmFormatModifier);
        }
    }

    return mods;
}

class PositiveImageDrm : public ImageDrmTest {};

TEST_F(PositiveImageDrm, Basic) {
    // See https://github.com/KhronosGroup/Vulkan-ValidationLayers/pull/2610
    // for more detailed checking, we could export the image to dmabuf
    // and then import it again (using VkImageDrmFormatModifierExplicitCreateInfoEXT)
    TEST_DESCRIPTION("Create image and imageView using VK_EXT_image_drm_format_modifier");
    RETURN_IF_SKIP(InitBasicImageDrm());

    // we just hope that one of these formats supports modifiers
    // for more detailed checking, we could also check multi-planar formats.
    auto format_list = {
        VK_FORMAT_B8G8R8A8_UNORM,
        VK_FORMAT_B8G8R8A8_SRGB,
        VK_FORMAT_R8G8B8A8_UNORM,
        VK_FORMAT_R8G8B8A8_SRGB,
    };

    for (auto format : format_list) {
        std::vector<uint64_t> mods =
            GetFormatModifier(format, VK_FORMAT_FEATURE_TRANSFER_DST_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
        if (mods.empty()) {
            continue;
        }

        // create image
        VkImageCreateInfo ci = vku::InitStructHelper();
        ci.flags = 0;
        ci.imageType = VK_IMAGE_TYPE_2D;
        ci.format = format;
        ci.extent = {128, 128, 1};
        ci.mipLevels = 1;
        ci.arrayLayers = 1;
        ci.samples = VK_SAMPLE_COUNT_1_BIT;
        ci.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
        ci.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
        ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
        ci.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;

        VkImageDrmFormatModifierListCreateInfoEXT mod_list = vku::InitStructHelper();
        mod_list.pDrmFormatModifiers = mods.data();
        mod_list.drmFormatModifierCount = mods.size();
        ci.pNext = &mod_list;

        vkt::Image image(*m_device, ci, vkt::no_mem);

        VkMemoryRequirements mem_reqs = image.MemoryRequirements();
        VkMemoryAllocateInfo alloc_info = vku::InitStructHelper();
        alloc_info.allocationSize = mem_reqs.size;
        if (!m_device->Physical().SetMemoryType(mem_reqs.memoryTypeBits, &alloc_info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
            GTEST_SKIP() << "Memory type not found";
        }

        vkt::DeviceMemory memory(*m_device, alloc_info);
        ASSERT_EQ(VK_SUCCESS, vk::BindImageMemory(device(), image, memory, 0));
        vkt::ImageView image_view = image.CreateView();
    }
}

TEST_F(PositiveImageDrm, ExternalMemory) {
    // https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/5649
    TEST_DESCRIPTION(
        "Create image with VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT and VkExternalMemoryImageCreateInfo in the pNext chain");

    AddRequiredExtensions(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME);
    RETURN_IF_SKIP(InitBasicImageDrm());

    const VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
    std::vector<uint64_t> mods = GetFormatModifier(format, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT);
    if (mods.empty()) {
        GTEST_SKIP() << "No valid Format Modifier found";
    }

    VkExternalMemoryImageCreateInfo external_info = vku::InitStructHelper();
    external_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;

    VkImageDrmFormatModifierListCreateInfoEXT drm_info = vku::InitStructHelper(&external_info);
    drm_info.drmFormatModifierCount = size32(mods);
    drm_info.pDrmFormatModifiers = mods.data();

    VkImageCreateInfo ci = vku::InitStructHelper(&drm_info);
    ci.imageType = VK_IMAGE_TYPE_2D;
    ci.format = format;
    ci.extent = {128, 128, 1};
    ci.mipLevels = 1;
    ci.arrayLayers = 1;
    ci.samples = VK_SAMPLE_COUNT_1_BIT;
    ci.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
    ci.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
    ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
    ci.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;

    {
        VkPhysicalDeviceImageDrmFormatModifierInfoEXT drm_format_modifier = vku::InitStructHelper();
        drm_format_modifier.sharingMode = ci.sharingMode;
        drm_format_modifier.queueFamilyIndexCount = ci.queueFamilyIndexCount;
        drm_format_modifier.pQueueFamilyIndices = ci.pQueueFamilyIndices;
        VkPhysicalDeviceExternalImageFormatInfo external_image_info = vku::InitStructHelper(&drm_format_modifier);
        external_image_info.handleType = static_cast<VkExternalMemoryHandleTypeFlagBits>(external_info.handleTypes);
        VkPhysicalDeviceImageFormatInfo2 image_info = vku::InitStructHelper(&external_image_info);
        image_info.format = ci.format;
        image_info.type = ci.imageType;
        image_info.tiling = ci.tiling;
        image_info.usage = ci.usage;
        image_info.flags = ci.flags;

        VkExternalImageFormatProperties external_image_properties = vku::InitStructHelper();
        VkImageFormatProperties2 image_properties = vku::InitStructHelper(&external_image_properties);

        if (const auto result = vk::GetPhysicalDeviceImageFormatProperties2(Gpu(), &image_info, &image_properties);
            result != VK_SUCCESS) {
            GTEST_SKIP() << "Unable to create image. VkResult = " << string_VkResult(result);
        }

        if ((external_image_properties.externalMemoryProperties.compatibleHandleTypes & external_info.handleTypes) !=
            external_info.handleTypes) {
            GTEST_SKIP() << "Unable to create image, VkExternalMemoryImageCreateInfo::handleTypes not supported";
        }
    }
    vkt::Image image(*m_device, ci, vkt::no_mem);

    VkMemoryDedicatedAllocateInfo dedicated_info = vku::InitStructHelper();
    dedicated_info.image = image;
    VkMemoryAllocateInfo alloc_info = vku::InitStructHelper(&dedicated_info);
    VkMemoryRequirements mem_reqs = image.MemoryRequirements();
    alloc_info.allocationSize = mem_reqs.size;
    if (!m_device->Physical().SetMemoryType(mem_reqs.memoryTypeBits, &alloc_info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
        GTEST_SKIP() << "Memory type not found";
    }

    vkt::DeviceMemory memory(*m_device, alloc_info);
    ASSERT_EQ(VK_SUCCESS, vk::BindImageMemory(device(), image, memory, 0));
}

TEST_F(PositiveImageDrm, GetImageSubresourceLayoutPlane) {
    RETURN_IF_SKIP(InitBasicImageDrm());

    VkFormat format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
    std::vector<uint64_t> mods = GetFormatModifier(format, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT, 2);
    if (mods.empty()) {
        GTEST_SKIP() << "No valid Format Modifier found";
    }

    VkImageDrmFormatModifierListCreateInfoEXT list_create_info = vku::InitStructHelper();
    list_create_info.drmFormatModifierCount = mods.size();
    list_create_info.pDrmFormatModifiers = mods.data();
    VkImageCreateInfo create_info = vku::InitStructHelper(&list_create_info);
    create_info.imageType = VK_IMAGE_TYPE_2D;
    create_info.format = format;
    create_info.extent.width = 64;
    create_info.extent.height = 64;
    create_info.extent.depth = 1;
    create_info.mipLevels = 1;
    create_info.arrayLayers = 1;
    create_info.samples = VK_SAMPLE_COUNT_1_BIT;
    create_info.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
    create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT;

    for (uint64_t mod : mods) {
        VkPhysicalDeviceImageDrmFormatModifierInfoEXT drm_format_modifier = vku::InitStructHelper();
        drm_format_modifier.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
        drm_format_modifier.drmFormatModifier = mod;
        VkPhysicalDeviceImageFormatInfo2 image_info = vku::InitStructHelper(&drm_format_modifier);
        image_info.format = format;
        image_info.type = create_info.imageType;
        image_info.tiling = create_info.tiling;
        image_info.usage = create_info.usage;
        image_info.flags = create_info.flags;
        VkImageFormatProperties2 image_properties = vku::InitStructHelper();
        if (vk::GetPhysicalDeviceImageFormatProperties2(Gpu(), &image_info, &image_properties) != VK_SUCCESS) {
            // Works with Mesa, Pixel 7 doesn't support this combo
            GTEST_SKIP() << "Required formats/features not supported";
        }
    }

    vkt::Image image(*m_device, create_info, vkt::no_mem);
    if (image.initialized() == false) {
        GTEST_SKIP() << "Failed to create image.";
    }

    VkImageSubresource subresource{VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT, 0, 0};
    VkSubresourceLayout layout{};
    vk::GetImageSubresourceLayout(*m_device, image, &subresource, &layout);
}

TEST_F(PositiveImageDrm, MutableFormat) {
    TEST_DESCRIPTION("use VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT with no VkImageFormatListCreateInfo .");
    RETURN_IF_SKIP(InitBasicImageDrm());

    std::vector<uint64_t> mods = GetFormatModifier(VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
    if (mods.empty()) {
        GTEST_SKIP() << "No valid Format Modifier found";
    }

    VkImageDrmFormatModifierListCreateInfoEXT mod_list = vku::InitStructHelper();
    mod_list.pDrmFormatModifiers = mods.data();
    mod_list.drmFormatModifierCount = mods.size();

    VkFormat formats = VK_FORMAT_R8G8B8A8_SNORM;
    VkImageFormatListCreateInfo format_list = vku::InitStructHelper(&mod_list);
    format_list.viewFormatCount = 1;
    format_list.pViewFormats = &formats;

    VkImageCreateInfo image_info = vku::InitStructHelper(&format_list);
    image_info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
    image_info.imageType = VK_IMAGE_TYPE_2D;
    image_info.format = VK_FORMAT_R8G8B8A8_UNORM;
    image_info.extent = {128, 128, 1};
    image_info.mipLevels = 1;
    image_info.arrayLayers = 1;
    image_info.samples = VK_SAMPLE_COUNT_1_BIT;
    image_info.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
    image_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
    image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
    image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
    vkt::Image image(*m_device, image_info, vkt::no_mem);

    VkMemoryRequirements mem_reqs = image.MemoryRequirements();
    VkMemoryAllocateInfo alloc_info = vku::InitStructHelper();
    alloc_info.allocationSize = mem_reqs.size;
    if (!m_device->Physical().SetMemoryType(mem_reqs.memoryTypeBits, &alloc_info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
        GTEST_SKIP() << "Memory type not found";
    }

    vkt::DeviceMemory memory(*m_device, alloc_info);
    ASSERT_EQ(VK_SUCCESS, vk::BindImageMemory(device(), image, memory, 0));
}

TEST_F(PositiveImageDrm, MutableExternalMemory) {
    TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8627");
    AddRequiredExtensions(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME);
    RETURN_IF_SKIP(InitBasicImageDrm());

    const VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
    std::vector<uint64_t> mods = GetFormatModifier(format, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT);
    if (mods.empty()) {
        GTEST_SKIP() << "No valid Format Modifier found";
    }

    VkFormat formats = VK_FORMAT_R8G8B8A8_SNORM;
    VkImageFormatListCreateInfo format_list = vku::InitStructHelper();
    format_list.viewFormatCount = 1;
    format_list.pViewFormats = &formats;

    VkExternalMemoryImageCreateInfo external_info = vku::InitStructHelper(&format_list);
    external_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;

    VkImageDrmFormatModifierListCreateInfoEXT drm_info = vku::InitStructHelper(&external_info);
    drm_info.drmFormatModifierCount = size32(mods);
    drm_info.pDrmFormatModifiers = mods.data();

    VkImageCreateInfo ci = vku::InitStructHelper(&drm_info);
    ci.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
    ci.imageType = VK_IMAGE_TYPE_2D;
    ci.format = format;
    ci.extent = {128, 128, 1};
    ci.mipLevels = 1;
    ci.arrayLayers = 1;
    ci.samples = VK_SAMPLE_COUNT_1_BIT;
    ci.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
    ci.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
               VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
    ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
    ci.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;

    {
        VkPhysicalDeviceImageDrmFormatModifierInfoEXT drm_format_modifier = vku::InitStructHelper(&format_list);
        drm_format_modifier.sharingMode = ci.sharingMode;
        drm_format_modifier.queueFamilyIndexCount = ci.queueFamilyIndexCount;
        drm_format_modifier.pQueueFamilyIndices = ci.pQueueFamilyIndices;
        VkPhysicalDeviceExternalImageFormatInfo external_image_info = vku::InitStructHelper(&drm_format_modifier);
        external_image_info.handleType = static_cast<VkExternalMemoryHandleTypeFlagBits>(external_info.handleTypes);
        VkPhysicalDeviceImageFormatInfo2 image_info = vku::InitStructHelper(&external_image_info);
        image_info.format = ci.format;
        image_info.type = ci.imageType;
        image_info.tiling = ci.tiling;
        image_info.usage = ci.usage;
        image_info.flags = ci.flags;

        VkExternalImageFormatProperties external_image_properties = vku::InitStructHelper();
        VkImageFormatProperties2 image_properties = vku::InitStructHelper(&external_image_properties);

        if (const auto result = vk::GetPhysicalDeviceImageFormatProperties2(Gpu(), &image_info, &image_properties);
            result != VK_SUCCESS) {
            GTEST_SKIP() << "Unable to create image. VkResult = " << string_VkResult(result);
        }

        if ((external_image_properties.externalMemoryProperties.compatibleHandleTypes & external_info.handleTypes) !=
            external_info.handleTypes) {
            GTEST_SKIP() << "Unable to create image, VkExternalMemoryImageCreateInfo::handleTypes not supported";
        }
    }
    vkt::Image image(*m_device, ci, vkt::no_mem);

    VkMemoryDedicatedAllocateInfo dedicated_info = vku::InitStructHelper();
    dedicated_info.image = image;
    VkMemoryAllocateInfo alloc_info = vku::InitStructHelper(&dedicated_info);
    VkMemoryRequirements mem_reqs = image.MemoryRequirements();
    alloc_info.allocationSize = mem_reqs.size;
    if (!m_device->Physical().SetMemoryType(mem_reqs.memoryTypeBits, &alloc_info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
        GTEST_SKIP() << "Memory type not found";
    }

    vkt::DeviceMemory memory(*m_device, alloc_info);
    ASSERT_EQ(VK_SUCCESS, vk::BindImageMemory(device(), image, memory, 0));
}

TEST_F(PositiveImageDrm, GetImageDrmFormatModifierProperties) {
    TEST_DESCRIPTION("Use vkGetImageDrmFormatModifierPropertiesEXT");
    RETURN_IF_SKIP(InitBasicImageDrm());

    std::vector<uint64_t> mods = GetFormatModifier(VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
    if (mods.empty()) {
        GTEST_SKIP() << "No valid Format Modifier found";
    }

    VkImageDrmFormatModifierListCreateInfoEXT mod_list = vku::InitStructHelper();
    mod_list.pDrmFormatModifiers = mods.data();
    mod_list.drmFormatModifierCount = mods.size();

    VkImageCreateInfo image_info = vku::InitStructHelper(&mod_list);
    image_info.imageType = VK_IMAGE_TYPE_2D;
    image_info.format = VK_FORMAT_R8G8B8A8_UNORM;
    image_info.extent = {128, 128, 1};
    image_info.mipLevels = 1;
    image_info.arrayLayers = 1;
    image_info.samples = VK_SAMPLE_COUNT_1_BIT;
    image_info.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
    image_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
    image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
    image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
    vkt::Image image(*m_device, image_info);

    VkImageDrmFormatModifierPropertiesEXT props = vku::InitStructHelper();
    vk::GetImageDrmFormatModifierPropertiesEXT(device(), image, &props);
}

TEST_F(PositiveImageDrm, PhysicalDeviceImageDrmFormatModifierInfoExclusive) {
    TEST_DESCRIPTION("Use vkPhysicalDeviceImageDrmFormatModifierInfo with VK_SHARING_MODE_EXCLUSIVE");
    AddRequiredExtensions(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME);
    RETURN_IF_SKIP(InitBasicImageDrm());

    VkPhysicalDeviceImageDrmFormatModifierInfoEXT drm_format_modifier = vku::InitStructHelper();
    drm_format_modifier.sharingMode = VK_SHARING_MODE_EXCLUSIVE;

    VkPhysicalDeviceExternalImageFormatInfo external_image_info = vku::InitStructHelper(&drm_format_modifier);
    external_image_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;

    VkPhysicalDeviceImageFormatInfo2 image_info = vku::InitStructHelper(&external_image_info);
    image_info.format = VK_FORMAT_R8G8B8A8_UNORM;
    image_info.type = VK_IMAGE_TYPE_2D;
    image_info.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
    image_info.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
    image_info.flags = 0;

    VkExternalImageFormatProperties external_image_properties = vku::InitStructHelper();
    VkImageFormatProperties2 image_properties = vku::InitStructHelper(&external_image_properties);

    vk::GetPhysicalDeviceImageFormatProperties2(Gpu(), &image_info, &image_properties);
}

TEST_F(PositiveImageDrm, PhysicalDeviceImageDrmFormatModifierInfoConcurrent) {
    TEST_DESCRIPTION("Use vkPhysicalDeviceImageDrmFormatModifierInfo with VK_SHARING_MODE_CONCURRENT");
    AddRequiredExtensions(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME);
    RETURN_IF_SKIP(InitBasicImageDrm());

    uint32_t queue_family_property_count = 0;
    vk::GetPhysicalDeviceQueueFamilyProperties2(Gpu(), &queue_family_property_count, nullptr);
    if (queue_family_property_count < 2) {
        GTEST_SKIP() << "pQueueFamilyPropertyCount is not 2 or more";
    }
    std::vector<VkQueueFamilyProperties2> queue_family_props(queue_family_property_count);
    vk::GetPhysicalDeviceQueueFamilyProperties2(Gpu(), &queue_family_property_count, nullptr);

    VkPhysicalDeviceImageDrmFormatModifierInfoEXT drm_format_modifier = vku::InitStructHelper();
    drm_format_modifier.sharingMode = VK_SHARING_MODE_CONCURRENT;
    drm_format_modifier.queueFamilyIndexCount = 2;
    uint32_t queue_family_indices[2] = {0, 1};
    drm_format_modifier.pQueueFamilyIndices = queue_family_indices;

    VkPhysicalDeviceExternalImageFormatInfo external_image_info = vku::InitStructHelper(&drm_format_modifier);
    external_image_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;

    VkPhysicalDeviceImageFormatInfo2 image_info = vku::InitStructHelper(&external_image_info);
    image_info.format = VK_FORMAT_R8G8B8A8_UNORM;
    image_info.type = VK_IMAGE_TYPE_2D;
    image_info.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
    image_info.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
    image_info.flags = 0;

    VkExternalImageFormatProperties external_image_properties = vku::InitStructHelper();
    VkImageFormatProperties2 image_properties = vku::InitStructHelper(&external_image_properties);

    vk::GetPhysicalDeviceImageFormatProperties2(Gpu(), &image_info, &image_properties);
}
